package com.glodon.paas.databag.controller;

import com.glodon.paas.account.api.oauth1.AccessValidationResponse;
import com.glodon.paas.account.sdk.oauth1.web.OAuthFilter;
import com.glodon.paas.databag.api.bean.DatabagDto;
import com.glodon.paas.databag.api.bean.ResourceDto;
import com.glodon.paas.databag.api.bean.TaskDto;
import com.glodon.paas.databag.service.DatabagService;
import com.glodon.paas.databag.service.TaskService;
import com.glodon.paas.job.JobConstants;
import com.glodon.paas.job.model.TaskStatus;
import com.glodon.paas.job.util.JsonUtil;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 处理所有文件相关的资源.
 * 
 * @author botao.liao
 * 
 */
@Controller
@RequestMapping("/bag")
public class DatabagController {
    private final Logger logger = LoggerFactory.getLogger(DatabagController.class);
    private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private final ExecutorService pool = Executors.newFixedThreadPool(5);
    @Value("${databag.thumbnail.defaultsize:64}")
    private final String DEFAULT_THUMBNAIL_SIZE = "64";

    @Autowired
    private DatabagService databagService;
    @Autowired
    private TaskService taskService;

    @RequestMapping(value = "/{type}", method = RequestMethod.POST)
    @ResponseBody
    public String submitJob(HttpServletRequest request, @PathVariable("type") String type, @RequestBody String body)
            throws IOException {
        logger.info("incomming job {} : {}", type, body);
        body = URLDecoder.decode(body, "utf-8");
        DatabagDto dto = JsonUtil.jsonToObject(body, DatabagDto.class);
        dto.setType(type);
        dto.setUserId(getOwnerId(request));
        DatabagDto databag = databagService.create(dto);

        Map<String, String> result = new HashMap<String, String>();
        result.put("databagId", databag.getId());
        return JsonUtil.mapToJson(result);
    }

    @RequestMapping(value = "/{databagId}", method = RequestMethod.GET)
    @ResponseBody
    public String queryByJobId(HttpServletRequest request, HttpServletResponse response,
            @PathVariable("databagId") String databagId) throws IOException {
        DatabagDto dto = databagService.get(databagId);
        String jsonResult = convert2Json(dto);
        return jsonResult;
    }

    @RequestMapping(value = "/seed/{source}/{localId}/{version}", method = RequestMethod.GET)
    @ResponseBody
    public String queryByMeta(HttpServletRequest request, HttpServletResponse response,
            @PathVariable("source") String source, @PathVariable("localId") String localId,
            @PathVariable("version") String version) throws IOException {
        List<DatabagDto> dtos = databagService.findByMetadata(source, localId, version);
        List<String> jsons = new ArrayList<String>();
        for (DatabagDto job : dtos) {
            jsons.add(convert2Json(job));
        }
        return JsonUtil.objectToJson(jsons);
    }

    private String convert2Json(DatabagDto dto) {
        Map<String, String> result = new HashMap<String, String>();
        result.put(JobConstants.JOB_ID, dto.getId());
        result.put(JobConstants.JOB_START_TIME, dateFormat.format(dto.getStartTime()));
        if (dto.getEndTime() == null) {// 状态未知
            result.put(JobConstants.TASK_PROGRESS, "processing");
        } else {
            result.put(JobConstants.TASK_PROGRESS, JobConstants.JOB_COMPLETE);
            result.put(JobConstants.JOB_END_TIME, dateFormat.format(dto.getEndTime()));
            result.put(JobConstants.OUTPUT, dto.getOutput());
        }
        return JsonUtil.objectToJson(result);
    }

    /**
     * 获取thumbnail.
     * 
     * @param jobId
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/{databagId}/thumbnail", method = RequestMethod.GET)
    public void getThumbnail(@PathVariable("databagId") String databagId, HttpServletResponse resp) throws IOException {
        getThumbnail(databagId, DEFAULT_THUMBNAIL_SIZE, resp);
    }

    /**
     * 获取thumbnail.
     * 
     * @param jobId
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/{databagId}/thumbnail/{size}", method = RequestMethod.GET)
    public void getThumbnail(@PathVariable("databagId") String databagId, @PathVariable String size,
            HttpServletResponse resp) throws IOException {
        logger.debug("request thumbnail for databagId:{}", databagId);
        ResourceDto thumbnail = databagService.getThumbnail(databagId, size);
        resp.setContentType(thumbnail.getMime());
        cacheResult(resp);
        InputStream is = thumbnail.getInputStream();
        IOUtils.copy(is, resp.getOutputStream());
        resp.flushBuffer();
    }

    /**
     * 根据mime类型获取资源.
     * 
     * @param jobId
     * @param mime
     * @param os
     */
    @RequestMapping(value = "/{databagId}/mime/{mime}/**", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public List<String> getResourceByMime(@PathVariable("databagId") String databagId,
            @PathVariable("mime") String mime, HttpServletResponse resp) throws IOException {
        logger.debug("request mime \"{}\" for databagId:{}", mime, databagId);
        List<String> resourceByMime = databagService.getResourceByMime(databagId, mime);
        return resourceByMime;
    }

    /**
     * 获取生成数据包时的document中的原始数据.
     * 
     * @param databagId
     * @param download
     * @param resp
     * @throws IOException
     */
    @RequestMapping(value = "/{databagId}/resource", method = RequestMethod.GET)
    public void getResource(@PathVariable("databagId") String databagId,
            @RequestParam(required = false, defaultValue = "false", value = "download") boolean download,
            HttpServletResponse resp) throws IOException {
        ResourceDto resource = databagService.getResource(databagId);
        resp.setContentType(resource.getMime());
        cacheResult(resp);
        InputStream is = resource.getInputStream();
        IOUtils.copy(is, resp.getOutputStream());
        resp.flushBuffer();
    }

    /**
     * 根据相对路径获取资源.
     * 
     * @param jobId
     * @param fileName
     * @param os
     */
    @RequestMapping(value = "/{databagId}/path/**", method = RequestMethod.GET)
    public void getResourceByPath(@PathVariable("databagId") String databagId,
            @RequestParam(required = false, defaultValue = "false", value = "download") boolean download,
            HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String path = (String) req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        int beginIndex = ("/bag/" + databagId + "/path/").length();
        String fileName = path.substring(beginIndex);
        logger.debug("request resource \"{}\" for databagId:{}", fileName, databagId);
        ResourceDto result = databagService.getResourceByPath(databagId, fileName);
        resp.setContentType(result.getMime());
        cacheResult(resp);
        if (download == true) {
            String name = fileName;
            int nameIndex = fileName.lastIndexOf("/");
            if (nameIndex > 0) {
                name = fileName.substring(nameIndex + 1);
            }
            resp.addHeader("Content-Disposition", "attachment; filename=\"" + name + "\"");
        }
        InputStream is = result.getInputStream();
        IOUtils.copy(is, resp.getOutputStream());
        resp.flushBuffer();
    }

    @RequestMapping(value = "/{databagId}/progress", method = RequestMethod.GET)
    @ResponseBody
    public String queryProgress(@PathVariable("databagId") String databagId, HttpServletResponse resp)
            throws IOException {
        TaskDto taskDto = taskService.getTaskByDatabagId(databagId);
        TaskStatus status = taskDto.getStatus();
        String result = null;
        if (TaskStatus.running.equals(status) || TaskStatus.created.equals(status) || TaskStatus.success.equals(status)) {
            result = taskDto.getProgress() == null ? "0" : taskDto.getProgress().toString();
        } else {// 任务失败
            result = "-1"; // 约定-1代表任务失败
        }
        if (TaskStatus.success.equals(status)) {
            cacheResult(resp);
        }
        return result;
    }

    /**
     * 删除数据包资源.
     * 
     * @param jobId
     * @param resp
     */
    @RequestMapping(value = "/{databagId}", method = RequestMethod.DELETE)
    public void deleteResource(@PathVariable final String databagId,
            @RequestParam(required = false, value = "alternatePublic") final String alternatePublic,
            HttpServletResponse resp) {
        logger.info("delete databag for databagId:{}", databagId);
        pool.execute(new Runnable() {
            @Override
            public void run() {
                databagService.deleteResource(databagId, alternatePublic);
            }
        });
        resp.setStatus(HttpServletResponse.SC_OK);
    }

    private String getOwnerId(HttpServletRequest request) {
        AccessValidationResponse response = OAuthFilter.getValidationResponse(request);
        String userId = response.getUserId();
        return userId;
    }

    private HttpServletResponse cacheResult(HttpServletResponse resp) {
        resp.addHeader("Cache-Control", "max-age=315360000000");
        return resp;
    }
}
